package com.tanhua.server.interceptor;

import com.tanhua.domain.db.User;
import com.tanhua.domain.mongo.Administration;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.dubbo.api.mongo.AdministrationApi;
import com.tanhua.server.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 自定义拦截器
 * 1、在请求到达控制器之前，预先处理一些操作
 * 2、获取请求头中的token，获取redis中中用户，转换为对象
 * 3. 存储对象绑定到线程对象上（ThreadLocal）
 */
@Component
@Slf4j
public class TokenInterceptor implements HandlerInterceptor {
    
    // 依赖注入：去ioc容器找UserService类型的对象，赋值给userService
    @Autowired
    private UserService userService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Reference
    private AdministrationApi administrationApi;
    @Reference
    private UserInfoApi userInfoApi;
    
    /**
     * 处理请求执行执行
     *
     * @param request  请求对象
     * @param response 响应对象
     * @param handler  处理器（当前访问的controller）
     * @return 返回true表示放行；否则拒绝访问
     * <p>
     * request对象
     * request.getRemoteHost() 获取访问着ip
     * request.getRequestURL() 获取访问的资源（访问路径）
     */
    @Override
    public boolean preHandle(
            HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("拦截器处理请求,访问这的IP：{},访问的资源：{}",
                request.getRemoteHost(), request.getRequestURL());
        
        //1. 获取请求头中的token; 相当于@RequestHeader("Authorization")
        String token = request.getHeader("Authorization");
        if (StringUtils.isEmpty(token)) {
            response.setStatus(401);
            return false; // 认证失败，不放行
        }
        
        //2. 从redis中获取用户的json字符串
        //3. 用户的json字符串转换为对象 (UserService中有实现)
        User user = userService.findUserByToken(token);
        if (user == null) {
            response.setStatus(401);
            return false;
        }
//调用api查询用户冻结记录
        Administration administration = administrationApi.queryFreeze(user.getId());
//判断对象是否存在且状态为1：冻结登录
        if (administration != null && administration.getFreezingRange() == 1) {
            //从redis里查询是否有冻结记录(自定义字符串+用户id+范围)
            String key = "freeze_" + user.getId() + "_" + administration.getFreezingRange();
            String value = redisTemplate.opsForValue().get(key);
            //判断redis里是否有值
            if (value != null) {
                //不为空，说明还在冻结时间里
                response.setStatus(401);
                return false;
            }
            //判断用户状态和redis里的记录
            if (administration.getFreezingRange() == 1 && value == null) {
                //说明冻结时间过了，删除用户状态
                administrationApi.remove(user.getId());
                //修改用户状态为：1正常
                userInfoApi.changeStatus(user.getId(), "1");
                return true;
            }
        }
        
        
        //4. 把登陆用户对象存储？
        UserHolder.set(user);
        return true;
    }
}
